/**
 * @(#)Security.java
 *
 * Copyright: Copyright (c) 2003 Carnegie Mellon University
 *
 * This program is the implementation of the original system in the Assignment 2 of "Architectures
 * of Software Systems" class. For the details of each classes, please refer to the provided javadoc
 * documents. You will also find some useful information such as implementation decisions, coding
 * standards, and naming conventions in the README file.
 */


import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;




/**
 * This class represents a logic node which is responsible for providing high-level data access
 * methods to clients using RMI mechanism. It depends on the functionalities of data node
 * which is made available also using RMI mechanism, thus acting as a "bridge" between client nodes
 * and the data node.
 *
 * @author Jung Soo Kim
 * @version 1.0
 */
public class Security extends UnicastRemoteObject implements RISecurity {

	private static final String SECURITY_NAME = "Security";
    private static final String LOGIC_NAME = "Logic";
    private static final String DATA_NAME  = "Data";

    /**
     * Remote reference to data node.
     */
    protected RIData rmiDataNode;
    protected RILogic rmiLogicNode;
    protected boolean isValid = false;
    protected String sUserID = "";
    
    /**
     * Constructs a logic node. A remote reference to the data node is acquired at the time of
     * creation.
     *
     * @param sDataName the name of data node
     */
    /*
    public Logic(String sDataName)
           throws RemoteException, NotBoundException, MalformedURLException {
        // Get the remote reference to data node.
        this.rmiDataNode = (RIData) Naming.lookup(sDataName);
    }
    */
    /*
    public Security(String sDataName)
            throws RemoteException, NotBoundException, MalformedURLException {
         // Get the remote reference to data node.
         this.rmiDataNode = (RIData) Naming.lookup(sDataName);
     }
	*/
    
    public Security(String sLogicName)
            throws RemoteException, NotBoundException, MalformedURLException {
         // Get the remote reference to data node.
         this.rmiLogicNode = (RILogic) Naming.lookup(sLogicName);
         
         try {
 			MyLogger.setup();
 		} catch (IOException e) {
 			e.printStackTrace();
 			throw new RuntimeException("Problems with creating the log files");
 		}
      }
    
    private final static Logger LOGGER = Logger.getLogger(Security.class
			.getName());

	public void writeLog(String sID, String sCmd) {
		// Set the LogLevel to Severe, only severe Messages will be written
		//LOGGER.setLevel(Level.SEVERE);
		//LOGGER.severe("Info Log");
		//LOGGER.warning("Info Log");
		LOGGER.info("ID:" + sID + "       Command:" + sCmd + "\n");
		//LOGGER.finest("Really not important");

		// Set the LogLevel to Info, severe, warning and info will be written
		// Finest is still not written
		//LOGGER.setLevel(Level.INFO);
		//LOGGER.severe("Info Log");
		//LOGGER.warning("Info Log");
		//LOGGER.info("Info Log");
		//LOGGER.finest("Really not important");
	}

    
    public boolean checkIDPwd(String sUserID, String sPassword) 
    	    throws RemoteException {
    	
    	System.out.println("id : " + sUserID + ", pwd : " + sPassword);
    	
    	if (sUserID.compareTo("admin") == 0 && sPassword.compareTo("4321") == 0)    
    	{
    		isValid = true;
    		System.out.println("result1 : " +  isValid);
    		this.rmiLogicNode.setLoginID(sUserID);
    		this.sUserID = sUserID;    		
    	}
    	else
    	{
    		isValid = false;
    		System.out.println("result2 : " +  isValid);   
    		this.sUserID = "invalid";
    	}
    	
    	this.writeLog(this.sUserID, "Authentication");
    	return isValid;
    }
    /**
     * List all students.
     *
     * @return a string result of command processing
     */
    public String getAllStudents()
                  throws RemoteException {
    	/*
        // Get all student records.
        ArrayList vStudent = this.rmiDataNode.getAllStudentRecords();

        // Construct a list of student information and return it.
        String sReturn = "";
        for (int i=0; i<vStudent.size(); i++) {
            sReturn += (i == 0 ? "" : "\n") + ((Student) vStudent.get(i)).toString();
        }
        return sReturn;
        */
    	
    	//Security logger = new Security();
		
		this.writeLog(sUserID, "getAllStudents");
		
    	if (isValid)
    		return this.rmiLogicNode.getAllStudents();
    	else
    		return "invalid !!!!!!!!!!";
    }

    /**
     * List all courses.
     *
     * @return a string result of command processing
     */
    public String getAllCourses()
                  throws RemoteException {
    	/*
        // Get all course records.
        ArrayList vCourse = this.rmiDataNode.getAllCourseRecords();

        // Construct a list of course information and return it.
        String sReturn = "";
        for (int i=0; i<vCourse.size(); i++) {
            sReturn += (i == 0 ? "" : "\n") + ((Course) vCourse.get(i)).toString();
        }
        return sReturn;
        */
    	
    	this.writeLog(sUserID, "getAllCourses");
    	
    	if (isValid)
    		return this.rmiLogicNode.getAllCourses();
    	else
    		return "invalid !!!!!!!!!!";
    }

    /**
     * List students who registered for a course.
     *
     * @param sCID a string representing course ID
     * @param sSection a string representing course section
     * @return a string result of command processing
     */
    public String getRegisteredStudents(String sCID, String sSection)
                  throws RemoteException {
    	/*
        // Get the list of students who registered for the given course.
        Course objCourse = this.rmiDataNode.getCourseRecord(sCID, sSection);
        if (objCourse == null) {
            return "Invalid course ID or course section";
        }
        ArrayList vStudent = objCourse.getRegisteredStudents();

        // Construct a list of student information and return it.
        String sReturn = "";
        for (int i=0; i<vStudent.size(); i++) {
            sReturn += (i == 0 ? "" : "\n") + ((Student) vStudent.get(i)).toString();
        }
        return sReturn;
        */
    	this.writeLog(sUserID, "getRegisteredStudents");
    	
    	if (isValid)
        	return this.rmiLogicNode.getRegisteredStudents(sCID, sSection);
        else
    		return "invalid !!!!!!!!!!";
    }

    /**
     * List courses a student has registered for.
     *
     * @param sSID a string representing student ID
     * @return a string result of command processing
     */
    public String getRegisteredCourses(String sSID)
                  throws RemoteException {
    	/*
        // Get the list of courses the given student has registered for.
        Student objStudent = this.rmiDataNode.getStudentRecord(sSID);
        if (objStudent == null) {
            return "Invalid student ID";
        }
        ArrayList vCourse = objStudent.getRegisteredCourses();

        // Construct a list of course information and return it.
        String sReturn = "";
        for (int i=0; i<vCourse.size(); i++) {
            sReturn += (i == 0 ? "" : "\n") + ((Course) vCourse.get(i)).toString();
        }
        return sReturn;
        */
    	this.writeLog(sUserID, "getRegisteredCourses");
    	
    	if (isValid)
    		return this.rmiLogicNode.getRegisteredCourses(sSID);
    	else
    		return "invalid !!!!!!!!!!";
    }

    /**
     * List courses a student has completed.
     *
     * @param sSID a string representing student ID
     * @return a string result of command processing
     */
    public String getCompletedCourses(String sSID)
                  throws RemoteException {
    	/*
        // Get the list of courses the given student has completed.
        Student objStudent = this.rmiDataNode.getStudentRecord(sSID);
        if (objStudent == null) {
            return "Invalid student ID";
        }
        ArrayList vCourseID = objStudent.getCompletedCourses();

        // Construct a list of course information and return it.
        String sReturn = "";
        for (int i=0; i<vCourseID.size(); i++) {
            String sCID = (String) vCourseID.get(i);
            String sName = this.rmiDataNode.getCourseName(sCID);
            sReturn += (i == 0 ? "" : "\n") + sCID + " " + (sName == null ? "Unknown" : sName);
        }
        return sReturn;
        */
    	this.writeLog(sUserID, "getCompletedCourses");
    	
    	if (isValid)
    		return this.rmiLogicNode.getCompletedCourses(sSID);
    	else
    		return "invalid !!!!!!!!!!";
    }

    /**
     * Register a student for a course. Conflict check is done before making a registration.
     *
     * @param sSID a string representing student ID
     * @param sCID a string representing course ID
     * @param sSection a string representing course section
     * @return a string result of command processing
     */
    public String makeARegistration(String sSID, String sCID, String sSection)
                  throws RemoteException {
    	/*
        // Get the student and course records.
        Student objStudent = this.rmiDataNode.getStudentRecord(sSID);
        Course objCourse = this.rmiDataNode.getCourseRecord(sCID, sSection);
        if (objStudent == null) {
            return "Invalid student ID";
        }
        if (objCourse == null) {
            return "Invalid course ID or course section";
        }

        // Check if the given course conflicts with any of the courses the student has registered.
        ArrayList vCourse = objStudent.getRegisteredCourses();
        for (int i=0; i<vCourse.size(); i++) {
            if (((Course) vCourse.get(i)).conflicts(objCourse)) {
                return "Registration cconflicts";
            }
        }

        // Request validated. Proceed to register.
        this.rmiDataNode.makeARegistration(sSID, sCID, sSection);
        return "Successful!";
        */
    	this.writeLog(sUserID, "makeARegistration");
    	
    	if (isValid)
    	{
    		this.rmiLogicNode.makeARegistration(sSID, sCID, sSection);
    		return "Successful!";
    	}
    	else
    		return "invalid !!!!!!!!!!";
    }

    /**
     * Creates a logic node and starts it. Two parameters are expected, the first one as data node
     * name and the second one as logic node name.
     *
     * @param args array of input parameters
     */
    public static void main(String args[]) {
        // Check the number of parameters.
        if (args.length != 0) {
            System.out.println("Incorrect number of parameters");
            System.out.println("Usage: java Security");
            System.exit(1);
        }
/*
        try {
            // Create a logic node and make it available through RMI.
            Logic objLogic = new Logic(DATA_NAME);
            Naming.rebind(LOGIC_NAME, objLogic);
            System.out.println("Logic node is ready to serve.");

            // Wait for user interrupt.
            System.out.println("Press Enter to terminate.");
            System.in.read();

            // Clean up and finish.
            Naming.unbind(LOGIC_NAME);
            System.out.println("Logic node is leaving, bye. Press ctrl-c if the delay is too long.");
        }
        */
        try {
            // Create a logic node and make it available through RMI.
            Security objSecurity = new Security(LOGIC_NAME);
            Naming.rebind(SECURITY_NAME, objSecurity);
            System.out.println("Security node is ready to serve.");

            // Wait for user interrupt.
            System.out.println("Press Enter to terminate.");
            System.in.read();

            // Clean up and finish.
            Naming.unbind(SECURITY_NAME);
            System.out.println("Security node is leaving, bye. Press ctrl-c if the delay is too long.");
        }
        catch (java.rmi.ConnectException e) {
            // Show error message and quit.
            System.err.println("Java RMI error: check if rmiregistry is running.");
            System.exit(1);
	}
        catch (java.rmi.NotBoundException e) {
            // Show error message and quit.
            System.err.println("Java RMI error: check if logic node is running.");
            System.exit(1);
        }
        catch (Exception e) {
            // Dump the exception information for debugging.
            System.out.println("Unexpected exception at " + SECURITY_NAME);
            e.printStackTrace();
            System.exit(1);
        }
    }
}
